class Student {
    //成员变量:定义在方法的外部，类的内部
    //普通成员变量-->属于对象，访问方式:对象的引用=>“对象.”
    private String name; //姓名-->被private修饰的成员变量只能在当前类中使用
                         //   -->如果想要在类外访问，则需要提供相应的方法
    public int age;      //年龄

    //静态成员变量-->属于方法区,访问方式:类的引用=>“类名.”  静态成员变量的使用不依赖于对象
    public static String classRoom;//教室-->如果所有的学生都在同一个教室，那么对于每个对象来说，其classRoom的值是一样的
                                   //classRoom只需要所有对象共用一份即可，不需要为每个对象单独开辟一块空间专门保存classRoom
                                   //此时则直接可以在该成员变量前加上static关键字,且该成员变量就在对象当中存储了(堆上)，
                                   //而是在方法区中开辟内存进行存储，并且该成员变量是所有的实例化对象共用的，
                                   //所以并不推荐通过实例化对象引用来访问该成员变量 eg:student1.classRoom;虽然编译可以通过，但会报警告
    //静态成员变量初始化有两种:1.就地初始化 2.静态代码块初始化
    public static String classRoom1 = "109";    //就地初始化

    //这是实例化代码块，定义在类的里面的代码块(初始化普通成员变量)
    //在实例化一个对象时，实例化代码块比构造方法先执行，对成员变量先进行赋值
    {
        System.out.println("这是实例化代码块");
        this.name = "zhangsan";
        this.age = 18;
    }

    //这是静态代码块，用static修饰的代码块(初始化静态成员变量)
    //实例化一个对象时，执行顺序:静态代码块>实例化代码块>构造方法
    //静态代码块不管生成多少个对象，其只会执行一次(类首次被加载的时候,也可能是调用静态成员时)
    //如果有多个静态代码块，编译器编译时，会按顺序合并后依次执行
    //实例化代码块和构造方法只要实例化一个对象就执行一次
    static {
        System.out.println("这是静态代码块2");
        classRoom = "109";
        classRoom1 = "110";
    }
    static {
        System.out.println("这是静态代码块1");
        classRoom = "109";
        classRoom1 = "110";
    }
    //因为classRoom这个静态成员变量并不单单属于某一个实例化对象了
                                   //更推荐 " 类名. " 的方式来访问该静态成员变量 eg:Student.classRoom;表示该类的对象共用的静态成员变量
                                   //所以在Java中访问静态成员变量，并不需要先实例化一个对象，而是直接可以通过"类名."的方式直接进行访问

    //构造方法
    //-->是一种特殊的成员方法，方法名必须和类名相同，并且该方法没有返回值
    //-->构造方法在创建对象时由编译器自动调用，并且在对象的生命周期内只调用一次
    //-->只是为对象的成员进行初始化，并不负责为对象开辟空间
    //-->构造方法可以够成重载=>重载条件 1.方法名相同 2.形参列表不同
    //-->如果用户没有显示调用，Java会生成一份默认的无参构造函数
    //-->构造方法中，可以通过this调用其他的构造方法来简化代码
    //   =>this();通过这个语法调用当前类的其他构造方法
    //   =>只能在当前类的构造方法内部来使用
    //   =>只能在构造方法的第一行使用
    Student() {
        this("张三",18);
        System.out.println("无参的构造方法");
    }

    Student(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("带有2个参数的构造方法");
    }

    //成员方法
    //普通成员方法
    public void eat() {
        System.out.println(this.name + "正在吃饭!");
    }

    //获取成员变量name的方法
    public String getName() {
        return this.name;
    }

    //设置成员变量name的方法
    public void setName(String name) {
        this.name = name;
    }

    //静态成员方法-->普通成员方法存储在堆上，静态成员方法存储在方法区
    //         -->该成员方法是所有的实例化对象共用的，所以并不推荐通过实例化对象引用来调用该成员方法，虽然编译可以通过，但会报警告
    //         -->更推荐 " 类名. " 的方式来调用该静态成员方法，表示该类的对象共用的静态成员方法，所以在Java中调用静态成员方法
    //         -->并不需要先实例化一个对象，而是直接可以通过"类名."的方式直接进行调用，即静态成员方法的调用不依赖于对象
    public static void func() {
        System.out.println("这是一个静态成员方法!");
        //eat();        静态成员方法的内部，不能直接调用非静态成员方法和变量(静态成员方法的调用不依赖于对象,静态成员方法中没有this引用，因为this依赖于实例化对象)
        //this.eat();   这种方式也是不行的，这是因为静态方法在类被加载时就已经存在，而普通成员方法必须在创建对象实例后才存在
        //              静态成员方法比普通成员方法先存在，而普通成员方法必须对象实例化后才存在，并且this引用表示实例化对象的引用,this是依赖于实例化对象的
        //静态成员方法的内部，想要调用非静态成员方法，只能先实例化一个对象进行调用
        Student student = new Student();
        student.eat();
    }

    //如果静态成员变量被private修饰了，只能提供public修饰的静态成员方法让类外访问和使用静态成员变量(通过类名去访问)
    public static String getClassRoom() {
        return classRoom;
    }

    public static void setClassRoom(String classRoom) {
        Student.classRoom = classRoom;
    }

    //对象的打印-->重写toString()-->System.out.println(student);打印出来的才是对象的属性
    //右键-->生成-->toString()可以自动生产
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class Test
{
    public static int add(int a,int b) {
        return a + b;
    }

    public static void main(String[] args) {
        //这是一个普通代码块-->定义在方法里面的代码块
        {
            System.out.println("这是一个普通代码块");
            int x = 10;
            System.out.println(x);
        }

        //如果add()方法不加static修饰时，在这里直接使用会报错，这是因为Test类的普通成员方法的调用必须依赖实例化对象，
        //想要使用必须先实例化一个Test类对象，而static修饰的静态成员方法的调用则不需要依赖实例化对象，可以直接使用
//   eg:Test test = new Test();
//      System.out.println(test.add(3, 4));
        System.out.println(add(3, 4));


        Student.classRoom = "109";  //访问静态成员变量，并不需要先实例化一个对象，而是直接可以通过"类名."的方式直接进行访问
        //把实例化student对象后面的代码移上来了，方便对照
//      student.classRoom = "109";  //通过实例化对象引用来访问静态该成员变量，虽然编译可以通过，但会报警告-->并不推荐
//                                  //因为classRoom这个静态成员变量并不单单属于某一个实例化对象了
        Student.func();     //调用静态成员方法，并不需要先实例化一个对象，也是直接可以通过"类名."的方式直接进行访问
        //把实例化student对象后面的代码移上来了，方便对照
//      student.func();     //通过实例化对象引用来调用该静态成员方法，虽然编译可以通过，但会报警告-->并不推荐
//                          //因为func()这个静态成员方法也并不单单属于某一个实例化对象了
        //有些书上会把静态成员变量叫做类变量，静态成员方法叫做类方法，认为他们是属于类的，不是属于对象的(了解)

        //当类中的成员变量没有被初始化时
        Student student = new Student();
        System.out.println(student.getName());
        System.out.println(student.age);


        Student student1 = new Student();    //实例化一个对象
        student1.setName("张三");
        student1.age = 18;
        System.out.println(student1.getName());
        System.out.println(student1.age);
        student1.eat();

        Student student2 = new Student();   //实例化另一个对象
        student2.setName("李四");
        student2.age = 19;
        System.out.println(student2.getName());
        System.out.println(student2.age);
        student2.eat();

        //对象的打印
        //如果不重写toString()-->System.out.println(student);打印出来的是对象的地址-->Student@1b6d3586
        //重写toString()-->System.out.println(student);打印出来的是对象的属性-->Student{name='张三', age=18}
        //println()底层调用的是Object类的toString(),返回值就是对象的地址
        //因为Object类是Student类的父类，所以重写toString()方法后构成多态
        //此时调用的就是重写toString()方法，返回值就是所生成的对象属性
        System.out.println(student);
    }

}